<?php
class mcz_XHTML
{
	const STRICT_DTD = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
	const TRANSITIONAL_DTD = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
	const EOL = "\n";

	private $title = 'untitled page';
	private $charset = 'UTF-8';
	private $dtd = self::TRANSITIONAL_DTD;
	private $lang = 'fr';
	private $head = '';
	private $body = '';
	private $legal = false; //this is for legal xhtml content-type
	private $layout = '';
	private $layout_elements = array();
	private $jq_init;
	private $inner_css;
	public function __construct(array $values = null, $set = false)
	{
		$properties = array(
			'title',
			'charset',
			'dtd',
			'lang',
			'legal'
		);
		foreach($properties as $property)
		{
			if (!empty($values[$property]))
			{
				$this->$property = $values[$property];
			}
		}
		if ($set)
		{
			$this->css('/css/base');
			$this->js('/js/base');
		}
	}
	/**
	 *Link css stylesheet to the document
	 *
	 *@param string $href url of stylesheet
	 *@param string $media type of media (all,aural,screen,print,handled)
	 *@param string $id unique id
	 */
	public function css($href, $media = 'all', $id = '')
	{
		if (!empty($id))
		{
			$id = ' id="' . $id . '"';
		}
		$link = self::EOL . '<link' . $id . ' rel="stylesheet" type="text/css" href="' . $href . '" media="' . $media . '"/>';
		$this->head.= $link;
	}
	/**
	 *Add meta to the document
	 *
	 *@param string
	 *@param string
	 */
	public function meta($key, $value)
	{
		$html = '<meta name="' . $key . '" content="' . $value . '">';
		$this->head.= $html;
	}
	/**
	 *Link javascript to the document
	 *
	 *@param string $src url of script
	 */
	public function js($src)
	{
		$link = self::EOL . '<script type="text/javascript" src="' . $src . '"></script>';
		$this->head.= $link;
	}
	public function initJQuery($js)
	{
		$this->jq_init = $js;
	}
	public function innerCss($css)
	{
		$this->inner_css = $css;
	}
	/**
	 *Adds content to the body of the document. Please note there is no rollback.
	 *
	 *@param string $content any html content
	 */
	public function add($content)
	{
		$this->body.= $content;
	}
	/**
	 * add a layout string
	 *
	 * @param string $layout
	 */
	public function layout($layout)
	{
		$this->layout = $layout;
	}
	public function assign($layout_tag, $content = null)
	{
		if (is_array($layout_tag) and is_null($content))
		{
			foreach($layout_tag as $tag => $val)
			{
				$tag = '{' . $tag . '}';
				$this->layout_elements[$tag] = (string)$val;
			}
		}
		else
		{
			$layout_tag = '{' . $layout_tag . '}';
			$this->layout_elements[$layout_tag] = (string)$content;
		}
	}
	/**
	 *@return string html content
	 */
	public function __toString()
	{
		$content_type = 'text/html';
		if ($this->legal)
		{
			$content_type = 'application/xhtml+xml';
		}
		if (!empty($this->layout))
		{
			$this->body = $this->layout;
			$this->body = str_replace(array_keys($this->layout_elements) , array_values($this->layout_elements) , $this->body);
			$this->body = preg_replace('({[A-Z]+})', '', $this->body);
		}
		$jq_init = '';
		if (!empty($this->jq_init))
		{
			$jq_init = self::EOL . '<script type="text/javascript">' . self::EOL . '$(document).ready(function(){' . self::EOL . $this->jq_init . self::EOL . '});' . self::EOL . '</script>';
		}
		$inner_css = '';
		if (!empty($this->inner_css))
		{
			$inner_css = self::EOL . '<style type="text/css">' . self::EOL . $this->inner_css . self::EOL . '</style>';
		}
		$html = '<?xml version="1.0" encoding="' . $this->charset . '"?>' . self::EOL . $this->dtd . self::EOL . '<html xmlns="http://www.w3.org/1999/xhtml" lang="' . $this->lang . '">' . self::EOL . '<head>' . self::EOL . '<meta content="' . $content_type . '; charset=' . $this->charset . '" http-equiv="content-type" />' . self::EOL . '<title>' . $this->title . '</title>' . $this->head . $jq_init . $inner_css . self::EOL . '</head>' . self::EOL . '<body>' . self::EOL . $this->body . self::EOL . '</body>' . self::EOL . '</html>';
		return $html;
	}
	/**
	 *Return document content
	 *
	 *@return string $html html content
	 */
	public function content()
	{
		return $this->__toString();
	}
	/**
	 *Render document
	 *
	 *Call this method BEFORE any output
	 */
	public function render($die = false)
	{
		if ($this->legal)
		{
			header('Content-Type: application/xhtml+xml; charset=' . $this->charset);
		}
		else
		{
			header('Content-Type: text/html; charset=' . $this->charset);
		}
		echo $this->__toString();
		if ($die)
		{
			die();
		}
	}
	/**
	 * Create select
	 *
	 * Example use:
	 *
	 * $vals = array(
	 * 'singleVal1' => 'singleLabel1',
	 * 'grp1'=>array('grp1val1'=>'grp1val1','grp1val2'=>'grp1val2'),
	 * 'grp2'=>array('grp2val1'=>'grp2val1','grp2val2'=>'grp2val2')
	 * );
	 * $select = mcz_XHTML::mkSelect(array('values'=>$vals,'selected'=>'grp2val1'));
	 *
	 * @param array $aParams
	 * @return string
	 */
	static public function mkSelect(array $aParams)
	{
		if (isset($aParams['id']))
		{
			$id = ' id="' . $aParams['id'] . '"';
		}
		else
		{
			$id = '';
		}
		if (isset($aParams['class']))
		{
			$class = ' class="' . $aParams['class'] . '"';
		}
		else
		{
			$class = '';
		}
		if (isset($aParams['name']))
		{
			$name = ' name="' . $aParams['name'] . '"';
		}
		else
		{
			$name = '';
		}
		if (isset($aParams['script']))
		{
			$script = ' ' . $aParams['script'];
		}
		else
		{
			$script = '';
		}
		$html = self::EOL . '<select' . $name . $id . $class . $script . '>';
		if (isset($aParams['values']))
		{
			$selectedKey = '';
			if(isset($aParams['selected']))
			{
				$selectedKey = $aParams['selected'];
			}
			$labelLength = '';
			if(isset($aParams['labelLength']))
			{
				$labelLength = (int)$aParams['labelLength'];
			}

			foreach($aParams['values'] as $key => $value)
			{
				if(is_array($value))
				{
					$html.='<optgroup label="' . htmlspecialchars($key) . '">';
					foreach($value as $optkey => $optval)
					{
						$html.= self::mkOption($optkey, $optval, $selectedKey, $labelLength);
					}
					$html.='</optgroup>';
				}
				else
				{
					$html.= self::mkOption($key, $value, $selectedKey, $labelLength);
				}
			}
		}
		$html.= self::EOL . '</select>';
		return $html;
	}

	static private function mkOption($key, $value, $selected = '', $labelLength = null)
	{
		if ($key == $selected)
		{
			$selected = ' selected="selected"';
		}
		else
		{
			$selected = '';
		}

		if (!empty($labelLength))
		{
			if (strlen($value) >= $labelLength)
			{
				$value = substr($value, 0, $labelLength);
				$espace = strrpos($value, " ");
				$value = substr($value, 0, $espace) . " ...";
			}
		}
		return(self::EOL . ' <option' . $selected . ' label="' . htmlspecialchars($value) . '" value="' . htmlspecialchars($key) . '">' . htmlspecialchars($value) . '</option>');
	}

	static public function escapeJSArgs($string, $string_delimiter = '"', $add_delimiters = true)
	{
		if ($string_delimiter == '"')
		{
			$string = str_replace(array(
				"\r\n",
				"\n",
				'"'
			) , array(
				'\n',
				'\n',
				'\"'
			) , $string);
		}
		elseif ($string_delimiter == "'")
		{
			$string = str_replace(array(
				"\r\n",
				"\n",
				"'"
			) , array(
				'\n',
				'\n',
				"\'"
			) , $string);
		}
		else
		{
			trigger_error('delimiter should be single or double quote.', E_USER_ERROR);
		}
		if ($add_delimiters)
		{
			return $string_delimiter . $string . $string_delimiter;
		}
		return $string;
	}
}
